
import { isDate, isPlainObject } from './util';

// 保留这些特殊字符@、:、$、,、、[、]
function encode (val: string): string {
  return encodeURIComponent(val)
    .replace(/%40/g, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/gi, ',')
    .replace(/%20/g, '+')
    .replace(/%5B/gi, '[')
    .replace(/%5D/gi, ']')
}

/**
 * desc: 处理params参数，根据一些列规则，将参数拼接到url上(序列化params)
 * @param url    String  ajax url
 * @param params Object  ajax params
*/
export function buildURL(url: string, params?: any): string {
  if(!params) {
    return url;
  }

  // 键值对数组：[key1=val1, key2=val2]
  const parts: string[] = [];

  // 1、遍历params，获取键值对， 将值统一转成数组, 并且忽略空值(/null/undefined)
  Object.keys(params).forEach(key => {
    let value = params[key];
    // 忽略空值
    if(value == null || typeof value === 'undefined') {
      return;
    }
    let values: any[] = []
    // 2、数组类型：key前面需要拼接[] /base/get?foo[]=bar&foo[]=baz'
    Array.isArray(value)? (values = value,  key += '[]') :  (values = [value])

   // 3、遍历values数组， 判断每个值的类型， 对val值做不同处理
   // 3-1、组装数据格式：[key1=val1， key2=val2], 每一个键值对都保存到数组中，key和value都需要通过encodeURIComponent转义，`@`、`:`、`$`、`,`、` `、`[`、`]`这几个不转义
   values.forEach(val => {
    if (isDate(val)) {
      val = val.toISOString()
    } else if (isPlainObject(val)) {
      val = JSON.stringify(val)
    }
    parts.push(`${encode(key)}=${encode(val)}`)
   })
  })
  
  // 将组装数据格式([key1=val1, key2=val2])通过&符号连接， 得到params序列化后的参数
  let serializedParams = parts.join('&')
  // 删除原url中#hash, 保留url上已有参数
  if(serializedParams) {
    const markIndex = url.indexOf('#')
    if(markIndex > -1) {
      serializedParams = serializedParams.slice(0, markIndex)
    }
    url += (url.indexOf("?") > -1? "&": '?') + serializedParams
  }
 
  return url;
}